from typing import List
from src.logger import Logger
from multiprocessing import Process
from src.config import Config
from src.mq import MessageQueue

from src.adaptor.matlab import MatlabAdaptor
from src.adaptor.matlab_mock import MockedMatlabAdaptor

from src.consumer.mimo import MimoDecodeConsumer, MimoPlotConsumer


def init_matlab(mock: bool, config: Config):
    return (
        MatlabAdaptor(config.matlab.lib_path, config.matlab.assets_dir)
        if not mock
        else MockedMatlabAdaptor()
    )


def mimo_decode_worker(config: Config):
    matlab = init_matlab(config.lab_mimo_decode.mock, config)
    mq = MessageQueue(config.rabbit_mq.host, config.rabbit_mq.port)
    MimoDecodeConsumer(config.lab_mimo_decode.queue, mq.channel, matlab)
    mq.start_consuming()


def mimo_plot_worker(config: Config):
    matlab = init_matlab(config.lab_mimo_plot.mock, config)
    mq = MessageQueue(config.rabbit_mq.host, config.rabbit_mq.port)
    MimoPlotConsumer(config.lab_mimo_plot.queue, mq.channel, matlab)
    mq.start_consuming()


def bootstrap():
    config = Config()

    total_weight = config.lab_mimo_decode.weight + config.lab_mimo_plot.weight
    decode_workers = round(
        config.app.max_workers * config.lab_mimo_decode.weight / total_weight
    )
    plot_workers = config.app.max_workers - decode_workers

    processes: List[Process] = []

    Logger.Info(f"decode workers {decode_workers}")
    for _ in range(decode_workers):
        p = Process(target=mimo_decode_worker, args=(config,))
        p.start()
        processes.append(p)

    Logger.Info(f"plot workers {plot_workers}")
    for _ in range(plot_workers):
        p = Process(target=mimo_plot_worker, args=(config,))
        p.start()
        processes.append(p)

    try:
        for p in processes:
            p.join()
    except KeyboardInterrupt:
        for p in processes:
            p.terminate()


if __name__ == "__main__":
    bootstrap()
